//! SeaORM 角色服务实现

use ::entity::system::{
    sys_menu::{self, Entity as SysMenu},
    sys_role::{self, Entity as SysRole},
    sys_role_menu::{self, Entity as SysRoleMenu},
    sys_user_role::{self, Entity as SysUserRole},
};
use sea_orm::*;
use tracing::{error, info, instrument};
use utils::{
    response::{AppError, AppResult},
    sea_orm_service::SeaOrmService,
    rpc::convert_app_error_to_status,
};

use crate::rpc::pb::role::*;

/// 角色服务
#[derive(Clone)]
pub struct RoleService {
    orm_service: SeaOrmService,
}

impl RoleService {
    /// 创建新的角色服务实例
    pub fn new(db: DatabaseConnection) -> Self {
        Self {
            orm_service: SeaOrmService::new(db),
        }
    }

    /// 获取角色列表
    #[instrument(skip(self))]
    pub async fn get_role_list(&self, request: tonic::Request<GetRoleListReq>) -> Result<tonic::Response<GetRoleListRes>, tonic::Status> {
        let req = request.into_inner();
        info!("获取角色列表: {:?}", req);

        // 直接在这里实现业务逻辑，不再分离为 _impl 方法
        // 构建基础查询
        let query = SysRole::find()
            .apply_if(Some(req.name), |query, v| {
                query.filter(sys_role::Column::Name.like(format!("%{}%", v)))
            })
            .apply_if(Some(req.code), |query, v| {
                query.filter(sys_role::Column::Code.like(format!("%{}%", v)))
            })
            .apply_if(Some(req.status), |query, v| {
                query.filter(sys_role::Column::Status.eq(v as i16))
            })
            .order_by_asc(sys_role::Column::Sort)
            .order_by_desc(sys_role::Column::Id);

        let total = query
            .clone()
            .count(self.orm_service.db())
            .await
            .map_err(|e| {
                error!("获取角色总数失败: {:?}", e);
                convert_app_error_to_status(AppError::database_with_source("角色总数查询失败", e))
            })?;

        let roles = query.all(self.orm_service.db()).await.map_err(|e| {
            error!("查询角色列表失败: {:?}", e);
            convert_app_error_to_status(AppError::database_with_source("角色列表查询失败", e))
        })?;

        // 转换为响应格式
        let mut role_infos = Vec::new();
        for role in roles {
            let role_info = self.convert_role_to_info(role).await.map_err(convert_app_error_to_status)?;
            role_infos.push(role_info);
        }

        let result = GetRoleListRes {
            roles: role_infos,
            total: total as i32,
            code: 200,
            message: "获取角色列表成功".to_string(),
        };
        
        Ok(tonic::Response::new(result))
    }

    /// 获取角色详情
    #[instrument(skip(self))]
    pub async fn get_role_info(&self, request: tonic::Request<GetRoleInfoReq>) -> Result<tonic::Response<GetRoleInfoRes>, tonic::Status> {
        let req = request.into_inner();
        info!("获取角色详情: role_id={}", req.role_id);

        let role = SysRole::find_by_id(req.role_id)
            .one(self.orm_service.db())
            .await
            .map_err(|e| {
                error!("查询角色失败: {:?}", e);
                convert_app_error_to_status(AppError::database_with_source("角色查询失败", e))
            })?
            .ok_or_else(|| convert_app_error_to_status(AppError::not_found("角色不存在")))?;

        let role_info = self.convert_role_to_info(role).await.map_err(convert_app_error_to_status)?;

        let result = GetRoleInfoRes {
            role: Some(role_info),
            code: 200,
            message: "获取角色详情成功".to_string(),
        };
        
        Ok(tonic::Response::new(result))
    }

    /// 创建角色
    #[instrument(skip(self))]
    pub async fn create_role(&self, request: tonic::Request<CreateRoleReq>) -> Result<tonic::Response<CreateRoleRes>, tonic::Status> {
        let req = request.into_inner();
        let result = self.create_role_impl(req).await.map_err(convert_app_error_to_status)?;
        Ok(tonic::Response::new(result))
    }

    async fn create_role_impl(&self, req: CreateRoleReq) -> AppResult<CreateRoleRes> {
        info!("创建角色: {:?}", req);

        // 检查角色代码是否已存在
        let existing = SysRole::find()
            .filter(sys_role::Column::Code.eq(&req.code))
            .one(self.orm_service.db())
            .await
            .map_err(|e| {
                error!("检查角色代码失败: {:?}", e);
                AppError::database_with_source("角色代码检查失败", e)
            })?;

        if existing.is_some() {
            return Err(AppError::validation("角色代码已存在"));
        }

        // 开始事务
        let txn = self.orm_service.begin_transaction().await?;

        // 创建角色
        let role_model = sys_role::ActiveModel {
            name: Set(req.name),
            code: Set(req.code),
            remark: Set(req.description),
            parent_id: Set(req.parent_id),
            sort: Set(req.sort),
            status: Set(req.status as i16),
            created_at: Set(chrono::Utc::now().naive_utc()),
            ..Default::default()
        };

        let role_result = SysRole::insert(role_model).exec(&txn).await.map_err(|e| {
            error!("创建角色失败: {:?}", e);
            AppError::database_with_source("角色创建失败", e)
        })?;

        let role_id = role_result.last_insert_id;

        // 关联菜单权限
        if !req.menu_ids.is_empty() {
            self.bind_role_menus(&txn, role_id, &req.menu_ids).await?;
        }

        // 提交事务
        SeaOrmService::commit_transaction(txn).await?;

        info!("角色创建成功: role_id={}", role_id);
        Ok(CreateRoleRes {
            role_id,
            code: 200,
            message: "创建角色成功".to_string(),
        })
    }

    /// 更新角色
    #[instrument(skip(self))]
    pub async fn update_role(&self, request: tonic::Request<UpdateRoleReq>) -> Result<tonic::Response<UpdateRoleRes>, tonic::Status> {
        let req = request.into_inner();
        let result = self.update_role_impl(req).await.map_err(convert_app_error_to_status)?;
        Ok(tonic::Response::new(result))
    }

    async fn update_role_impl(&self, req: UpdateRoleReq) -> AppResult<UpdateRoleRes> {
        info!("更新角色: {:?}", req);

        // 检查角色是否存在
        let mut role = SysRole::find_by_id(req.role_id)
            .one(self.orm_service.db())
            .await
            .map_err(|e| {
                error!("查询角色失败: {:?}", e);
                AppError::database_with_source("角色查询失败", e)
            })?
            .ok_or_else(|| AppError::not_found("角色不存在"))?
            .into_active_model();

        // 检查角色代码是否冲突
        if role.code.as_ref() != &req.code {
            let existing = SysRole::find()
                .filter(sys_role::Column::Code.eq(&req.code))
                .filter(sys_role::Column::Id.ne(req.role_id))
                .one(self.orm_service.db())
                .await
                .map_err(|e| {
                    error!("检查角色代码失败: {:?}", e);
                    AppError::database_with_source("角色代码检查失败", e)
                })?;

            if existing.is_some() {
                return Err(AppError::validation("角色代码已存在"));
            }
        }

        // 开始事务
        let txn = self.orm_service.begin_transaction().await?;

        // 更新角色信息
        role.name = Set(req.name);
        role.code = Set(req.code);
        role.remark = Set(req.description);
        role.parent_id = Set(req.parent_id);
        role.sort = Set(req.sort);
        role.status = Set(req.status as i16);
        role.updated_at = Set(Some(chrono::Utc::now().naive_utc()));

        role.update(&txn).await.map_err(|e| {
            error!("更新角色失败: {:?}", e);
            AppError::database_with_source("角色更新失败", e)
        })?;

        // 重新绑定菜单权限
        // 先删除原有权限
        SysRoleMenu::delete_many()
            .filter(sys_role_menu::Column::RoleId.eq(req.role_id))
            .exec(&txn)
            .await
            .map_err(|e| {
                error!("删除角色菜单关联失败: {:?}", e);
                AppError::database_with_source("角色菜单关联删除失败", e)
            })?;

        // 添加新权限
        if !req.menu_ids.is_empty() {
            self.bind_role_menus(&txn, req.role_id, &req.menu_ids)
                .await?;
        }

        // 提交事务
        SeaOrmService::commit_transaction(txn).await?;

        info!("角色更新成功: role_id={}", req.role_id);
        Ok(UpdateRoleRes {
            code: 200,
            message: "更新角色成功".to_string(),
        })
    }

    /// 删除角色
    #[instrument(skip(self))]
    pub async fn delete_role(&self, request: tonic::Request<DeleteRoleReq>) -> Result<tonic::Response<DeleteRoleRes>, tonic::Status> {
        let req = request.into_inner();
        let result = self.delete_role_impl(req).await.map_err(convert_app_error_to_status)?;
        Ok(tonic::Response::new(result))
    }

    async fn delete_role_impl(&self, req: DeleteRoleReq) -> AppResult<DeleteRoleRes> {
        info!("删除角色: {:?}", req);

        if req.role_ids.is_empty() {
            return Err(AppError::validation("角色ID不能为空"));
        }

        let role_ids: Vec<i64> = req.role_ids.iter().map(|id| *id).collect();

        // 检查是否有用户使用这些角色
        let user_count = SysUserRole::find()
            .filter(sys_user_role::Column::RoleId.is_in(role_ids.clone()))
            .count(self.orm_service.db())
            .await
            .map_err(|e| {
                error!("检查用户角色关联失败: {:?}", e);
                AppError::database_with_source("用户角色关联检查失败", e)
            })?;

        if user_count > 0 {
            return Err(AppError::validation("无法删除，角色正在被用户使用"));
        }

        // 开始事务
        let txn = self.orm_service.begin_transaction().await?;

        // 删除角色菜单关联
        SysRoleMenu::delete_many()
            .filter(sys_role_menu::Column::RoleId.is_in(role_ids.clone()))
            .exec(&txn)
            .await
            .map_err(|e| {
                error!("删除角色菜单关联失败: {:?}", e);
                AppError::database_with_source("角色菜单关联删除失败", e)
            })?;

        // 删除角色
        let delete_result = SysRole::delete_many()
            .filter(sys_role::Column::Id.is_in(role_ids.clone()))
            .exec(&txn)
            .await
            .map_err(|e| {
                error!("删除角色失败: {:?}", e);
                AppError::database_with_source("角色删除失败", e)
            })?;

        // 提交事务
        SeaOrmService::commit_transaction(txn).await?;

        info!(
            "角色删除成功: 删除了 {} 个角色",
            delete_result.rows_affected
        );
        Ok(DeleteRoleRes {
            code: 200,
            message: format!("删除 {} 个角色成功", delete_result.rows_affected),
        })
    }

    /// 绑定用户角色
    #[instrument(skip(self))]
    pub async fn bind_roles_by_user_id(
        &self,
        request: tonic::Request<BindRolesByUserIdReq>,
    ) -> Result<tonic::Response<BindRolesByUserIdRes>, tonic::Status> {
        let req = request.into_inner();
        let result = self.bind_roles_by_user_id_impl(req).await.map_err(convert_app_error_to_status)?;
        Ok(tonic::Response::new(result))
    }

    async fn bind_roles_by_user_id_impl(
        &self,
        req: BindRolesByUserIdReq,
    ) -> AppResult<BindRolesByUserIdRes> {
        info!("绑定用户角色: {:?}", req);

        // 开始事务
        let txn = self.orm_service.begin_transaction().await?;

        // 先删除用户的所有角色
        SysUserRole::delete_many()
            .filter(sys_user_role::Column::UserId.eq(req.user_id))
            .exec(&txn)
            .await
            .map_err(|e| {
                error!("删除用户角色关联失败: {:?}", e);
                AppError::database_with_source("用户角色关联删除失败", e)
            })?;

        // 添加新的角色绑定
        if !req.role_ids.is_empty() {
            let user_roles: Vec<sys_user_role::ActiveModel> = req
                .role_ids
                .into_iter()
                .map(|role_id| sys_user_role::ActiveModel {
                    user_id: Set(req.user_id),
                    role_id: Set(role_id),
                })
                .collect();

            SysUserRole::insert_many(user_roles)
                .exec(&txn)
                .await
                .map_err(|e| {
                    error!("绑定用户角色失败: {:?}", e);
                    AppError::database_with_source("用户角色绑定失败", e)
                })?;
        }

        // 提交事务
        SeaOrmService::commit_transaction(txn).await?;

        info!("用户角色绑定成功: user_id={}", req.user_id);
        Ok(BindRolesByUserIdRes {
            code: 200,
            message: "用户角色绑定成功".to_string(),
        })
    }

    /// 转换角色模型为信息对象
    async fn convert_role_to_info(&self, role: sys_role::Model) -> AppResult<RoleInfo> {
        // 获取关联的菜单
        let menus = SysMenu::find()
            .inner_join(SysRole)
            .filter(sys_role_menu::Column::RoleId.eq(role.id))
            .all(self.orm_service.db())
            .await
            .map_err(|e| {
                error!("查询角色菜单失败: {:?}", e);
                AppError::database_with_source("角色菜单查询失败", e)
            })?;

        let menu_infos: Vec<MenuInfo> = menus
            .into_iter()
            .map(|menu| MenuInfo {
                id: menu.id,
                name: menu.name,
                path: menu.path,
                perm_code: menu.perm_code,
            })
            .collect();

        Ok(RoleInfo {
            id: role.id,
            name: role.name,
            code: role.code,
            description: role.remark.clone(),
            parent_id: role.parent_id,
            sort: role.sort,
            status: role.status as i32,
            remark: role.remark,
            created_at: role.created_at.to_string(),
            updated_at: role.updated_at.map(|t| t.to_string()).unwrap_or_default(),
            children: vec![],
            menus: menu_infos,
        })
    }

    /// 绑定角色菜单
    async fn bind_role_menus(
        &self,
        txn: &DatabaseTransaction,
        role_id: i64,
        menu_ids: &[i64],
    ) -> AppResult<()> {
        let role_menus: Vec<sys_role_menu::ActiveModel> = menu_ids
            .iter()
            .map(|&menu_id| sys_role_menu::ActiveModel {
                role_id: Set(role_id),
                menu_id: Set(menu_id),
            })
            .collect();

        SysRoleMenu::insert_many(role_menus)
            .exec(txn)
            .await
            .map_err(|e| {
                error!("绑定角色菜单失败: {:?}", e);
                AppError::database_with_source("角色菜单绑定失败", e)
            })?;

        Ok(())
    }

    #[instrument(skip(self))]
    pub async fn get_role_tree(&self, request: tonic::Request<GetRoleTreeReq>) -> Result<tonic::Response<GetRoleTreeRes>, tonic::Status> {
        let _req = request.into_inner();
        let result = self.get_role_tree_impl(_req).await.map_err(convert_app_error_to_status)?;
        Ok(tonic::Response::new(result))
    }

    async fn get_role_tree_impl(&self, _req: GetRoleTreeReq) -> AppResult<GetRoleTreeRes> {
        info!("RPC: 获取角色树请求");

        // 查询所有角色
        let roles = SysRole::find()
            .order_by_asc(sys_role::Column::Sort)
            .order_by_desc(sys_role::Column::Id)
            .all(self.orm_service.db())
            .await
            .map_err(|e| {
                error!("查询角色列表失败: {:?}", e);
                AppError::database_with_source("查询角色列表失败", e)
            })?;

        // 转换为树形结构（这里简化处理，直接返回平级列表）
        let mut role_tree = Vec::new();
        for role in roles {
            let role_info = self.convert_role_to_info(role).await?;
            role_tree.push(role_info);
        }

        Ok(GetRoleTreeRes {
            roles: role_tree,
            message: "成功".to_string(),
            code: 200,
        })
    }
}
